﻿#ifndef UDP_ACK_SERVER_H
#define UDP_ACK_SERVER_H

#include "tftp.h"

#include <QObject>
#include <QList>
#include <QtNetwork>


namespace TFTP {
class ServerWriteSession;
class ServerReadSession;

/**
* @brief TFTP 服务端
*/
class UdpAckServer : public QObject
{
    Q_OBJECT
public:
    /**
    * @brief 构造函数
    * @param addr 服务器绑定的地址
    * @param port 要将服务器绑定到的端口（默认值=69，如RFC中所示）
    * @note 访问端口需要Root访问权限
    */
    UdpAckServer(const QHostAddress &addr, quint16  port = 69);
    ~UdpAckServer();

signals:
    /**
    * @brief 接收文件已完成
    * @param dev QIODevice instance where the file was wrote
    * @param remotefilename 远程端文件的名称
    * @note  该信号在文件接收完成时发出
    */
    void receivedFile(QIODevice *dev, const QString remotefilename);

    /**
    * @brief 发送文件已完成
    * @param dev QIODevice instance from which the file was read
    * @param remotefilename远程端文件的名称
    * @note 该信号在文件发送完成时发出
    */
    void sentFile(QIODevice *dev, QString remotefilename);

protected slots:
    /**
     * @brief  从套接字接收数据时调用
     */
    void dataReceived();

protected:
    /**
    * @brief 查找包含提供的TransferInfo数据的写入实例
    * @param ti 要查找的写入实例的TransferInfo数据
    * @return
    * 指向写入会话的指针 如果不到
    * nullptr 如果找不到
    */
    ServerWriteSession *findWSession(const TransferInfo &ti);

    /**
    * @brief 查找包含提供的TransferInfo数据的读取实例
    * @param ti 要查找的读取实例的TransferInfo数据
    * @return
    * 指向读取会话的指针 如果不到
    * nullptr 如果找不到
    */
    ServerReadSession *findRSession(const TransferInfo &ti);

protected:
    QList<ServerWriteSession*> writes;   ///< 所有打开写入实例的列表
    QList<ServerReadSession*>  reads;    ///< 所有打开读取实例的列表
    QUdpSocket        * socket;          ///< UDP套接字
    QHostAddress        address;         ///< 目标地址
    quint16             port;            ///< 目标端口
};

};

#endif
